# -*- coding: utf-8 -*-
import binascii
import importlib
import sys
from PySide6.QtCore import Signal, QTimer, Qt
from PySide6.QtGui import QShortcut, QKeySequence
from PySide6.QtWidgets import QWidget, QMessageBox, QApplication
from loguru import logger

from utils.bytesHelper import SliceBytesSafe
from utils.filePathTools import GetFilesWithExtension
from plugins.gWMC01IICUI_ui import Ui_GWMC01IICForm


class GWMC01IICWindow(QWidget, Ui_GWMC01IICForm):
    """
    C01的IIC通信
    """
    # 声明带一个字典类型参数的信号
    c01IICSignal = Signal(dict)
    scriptDir = 'data/pyScript'
    runTimesCount = 0
    scriptName = ''

    # if not os.path.exists(scriptDir):
    #     os.makedirs(scriptDir)
    def __init__(self):
        super().__init__()
        # 加载UI
        self.setupUi(self)
        # 连接信号与槽
        self.SignalConnectInit()
        # 创建定时器
        self.TimerInit()
        # 添加快捷键
        self.ShortcutFun()
        # 引入公共程序
        from utils.common import commonProgram
        # 引入配置文件
        self.myConfig = commonProgram.EnableConfigHandler()
        print('TpIntWindow get config Version', self.myConfig.version)
        # 引入可控串口信息窗口
        self.ft4222Win = commonProgram.EnableFt4222(winSignal=self.c01IICSignal, RecvFt4222Data=self.RecvFt4222Data)

        # self.ft4222Win.show()
        self.btnRefreshScript.click()

    def CleanupSelf(self):
        """
        清理当前窗口并关闭，由其他其他程序调用
        :return:
        """
        try:
            # 停止并注销定时器
            self.timer_exec.stop()
            self.timer_exec.deleteLater()
            self.timer_delay.stop()
            self.timer_delay.deleteLater()
            self.close()  # 关闭当前窗口
            self.deleteLater()  # 释放子窗口资源
            print("TpIntWindow.__del__.ok")
        except Exception as err:
            print("TpIntWindow.__del__.error", err)

    def SignalConnectInit(self):
        """
        连接来自UI对象的信号与槽
        :return:
        """
        self.checkBoxTimerExec.stateChanged.connect(self.TimerExecFun)
        self.btnTpInt.clicked.connect(self.BtnTpIntFun)
        self.btnIntDHU.clicked.connect(self.BtnIntDHUFun)
        self.btnRefreshScript.clicked.connect(self.BtnRefreshScriptFun)
        self.btnOneExec.clicked.connect(self.HandExecFun)

    def BtnRefreshScriptFun(self):
        self.comboBoxScript.clear()
        fileList = GetFilesWithExtension(self.scriptDir, '.py', need_ext=False)
        for filename in fileList:
            self.comboBoxScript.addItem(filename)

    def BtnTpIntFun(self):
        dictData = {"data": {"level": False}, "type": "ctrl_gpio2"}
        self.SendDataHandle(dictData)
        dictData = {"data": {"level": True}, "type": "ctrl_gpio2"}
        self.SendDataHandle(dictData)
        dictData = {"data": {"portNum": 2}, "type": "read_gpio"}
        self.SendDataHandle(dictData)

    def BtnIntDHUFun(self):
        dictData = {"data": {"portNum": 3}, "type": "read_gpio"}
        self.SendDataHandle(dictData)

    def BtnSendDataFun(self):
        dataObj = 'test'
        dataDict = {"data": dataObj, "type": f"send_ascii", }
        self.SendDataHandle(dataDict)

    def TimerInit(self):
        """
        定时器创建与信号连接
        此处添加了定时器，一定要在 `CleanupSelf`中添加注销操作，否则切换测试项时不会失效，会一直以子线程运行
        :return:
        """
        self.timer_exec = QTimer()
        self.timer_exec.timeout.connect(self.HandExecFun)
        self.timer_delay = QTimer()
        self.timer_delay.timeout.connect(self.TimeDelayFun)

    def TimerExecFun(self):
        """
        定时执行
        :return:
        """
        if self.checkBoxTimerExec.isChecked():
            timeDelay = int(self.spinBoxExecTime.text())
            if timeDelay < 1:
                QMessageBox.critical(self, 'wrong data', '请输入 正确的 延时 ！')
                self.checkBoxTimerExec.setChecked(False)
                return None
            self.timer_exec.start(timeDelay)
            self.spinBoxExecTime.setEnabled(False)
        else:
            self.timer_exec.stop()
            self.spinBoxExecTime.setEnabled(True)

    def TimeDelayFun(self):
        self.timer_delay.stop()
        self.IntDHUAfterCheck()

    def IntDHUAfterCheck(self):
        if self.checkBoxHUReadSelect.isChecked():
            dataAddr = self.lineEditDataAddr.displayText().strip()
            if (len(dataAddr.strip()) < 1) or (not ("0x" in dataAddr)):
                QMessageBox.warning(self, "空数据", "请输入正确的数据地址！")
                return None
            dataLen = int(self.spinBoxReadLen.value())
            if dataLen < 1:
                QMessageBox.warning(self, "空数据", "请输入正确的读取长度！")
                return None
            # print('HandReadFun', dataStr)
            # if self.checkRemoveBytes.isChecked():
            #     dataStr = str(dataStr)
            input_s = dataAddr.strip().replace('0X', '')
            send_list = []
            addrLen = 0
            while input_s != '':
                addrLen += 1
                try:
                    num = int(input_s[0:2], 16)
                except ValueError:
                    # QMessageBox.critical(self, 'wrong data', '请输入十六进制数据，以空格分开!')
                    return None
                input_s = input_s[2:].strip()
                send_list.append(num)
            input_s = bytes(send_list)
            i2cData = {
                "slaveAddr": eval(self.lineEditSlaveAddr.text().strip()),
                "dataAddr": input_s,
                "dataLen": dataLen,
            }
            dictData = {"data": i2cData, "type": "read_hex", "options": {"addr": self.scriptName, "addrLen": 1}}
            self.SendDataHandle(dictData)
            # timeStr = QDateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
            # logger.info("self.SendDataHandle(dictData)" + timeStr)
        if self.checkBoxMCUGPIOSelect.isChecked():
            dictData = {"data": {"portNum": 3}, "type": "read_gpio"}
            self.SendDataHandle(dictData)
            # timeStr = QDateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
            # logger.info("self.SendDataHandle(dictData)" + timeStr)

    def CleanStatusFun(self):
        self.checkBoxTpIntStatus.setChecked(False)
        self.checkBoxSendDataStatus.setChecked(False)
        self.checkBoxIntDHUStatus.setChecked(False)
        self.checkBoxHUReadStatus.setChecked(False)
        self.checkBoxMCUGPIOStatus.setChecked(False)

    def HandExecFun(self):
        self.CleanStatusFun()
        if self.checkBoxIncreaseTimes.isChecked():
            self.runTimesCount += 1
            self.spinBoxTimesCount.setValue(self.runTimesCount)
        else:
            self.runTimesCount = self.spinBoxTimesCount.value()
        if self.checkBoxScriptSelect.isChecked():
            scriptFile = self.comboBoxScript.currentText().strip()
            selected_module = importlib.import_module(f"data.pyScript.{scriptFile}")
            selected_module = importlib.reload(selected_module)
            loaded_obj = selected_module.ScriptClass(self)
            loaded_obj.InItMainAll(self.runTimesCount)
            self.scriptName = loaded_obj.scriptName
            # dictData = {"data": f"Script {scriptFile} starts executing", "type": "status_c01IIC"}
            # self.SendDataHandle(dictData)
        if self.checkBoxTpIntSelect.isChecked():
            self.BtnTpIntFun()
            # timeStr = QDateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
            # logger.info("self.BtnTpIntFun()" + timeStr)
        if self.checkBoxSendDataSelect.isChecked():
            self.SendDataFun()
            # timeStr = QDateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
            # logger.info("self.SendDataFun()" + timeStr)
        if self.checkBoxIntDHUSelect.isChecked():
            self.BtnIntDHUFun()
            # timeStr = QDateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
            # logger.info("self.BtnIntDHUFun()" + timeStr)
        if self.checkBoxINTDHU.isChecked():
            return
        if self.checkBoxDelayTimeSelect.isChecked():
            self.timer_delay.start(int(self.spinBoxDelayTime.value()))
        else:
            self.IntDHUAfterCheck()

    def SendDataFun(self):
        send_data = self.plainTextEditSendData.toPlainText().strip()
        if len(send_data.strip()) < 1:
            QMessageBox.warning(self, "空数据", "请输入内容！")
            return None
        # hex发送
        input_s = send_data.strip()
        send_list = []
        while input_s != '':
            try:
                num = int(input_s[0:2], 16)
            except ValueError:
                # QMessageBox.critical(self, 'wrong data', '请输入十六进制数据，以空格分开!')
                return None
            input_s = input_s[2:].strip()
            send_list.append(num)
        input_s = bytes(send_list)
        i2cData = {
            "slaveAddr": eval(self.lineEditSlaveAddr.text().strip()),
            "writeData": input_s,
        }
        dictData = {"data": i2cData, "type": f"send_hex"}
        self.SendDataHandle(dictData)

    def ShortcutFun(self):
        """
        快捷键 F11 全屏
        快捷键 F5 清屏
        :return:
        """
        # 快捷键 F11
        self.screenStatus = 'Normal'
        screenShortcut = QShortcut(QKeySequence(Qt.Key_F11), self)
        screenShortcut.activated.connect(self.WindowSizeFun)
        self.setToolTip('全屏与退出全屏：\n               双击 或者 F11')
        # 快捷键 F5
        # screenShortcut2 = QShortcut(QKeySequence(Qt.Key_F5), self)
        # screenShortcut2.activated.connect(self.CleanFun)

    def WindowSizeFun(self):
        """
        控制窗口尺寸，此处为原大小（最小UI布局）或者全屏
        :return:
        """
        if self.screenStatus == 'Normal':
            self.showFullScreen()
            self.screenStatus = 'FullScreen'
        else:
            self.showNormal()
            self.screenStatus = 'Normal'

    def SendDataHandle(self, dataDict: dict):
        """
        发送信号或数据处理函数
        :param dataDict:
        :return:
        """
        # 发送信号处理
        dataObj = dataDict.get('data', '')
        typeValue = dataDict.get('type', 'null').strip()
        # 本窗口发送数据
        if "send_" in typeValue:
            self.c01IICSignal.emit(dataDict)
        elif "read_" in typeValue:
            self.c01IICSignal.emit(dataDict)
        elif "ctrl_gpio2" in typeValue:
            self.c01IICSignal.emit(dataDict)
        elif "read_gpio" in typeValue:
            self.c01IICSignal.emit(dataDict)
        elif 'TpInt_to_' in typeValue:
            # logger.info("Plugin窗口发往其他窗口的数据：", typeValue, dataObj)
            self.c01IICSignal.emit(dataDict)
        elif typeValue != None:
            logger.info(f"dataObj={dataObj}, typeValue={typeValue}")
        # do something

    def RecvFt4222Data(self, dictData: dict):
        """
        用于接收串口控制窗口发过来的信号或数据
        :param dictData:
        :return:
        """
        self.RecvDataHandle(dictData)

    def RecvDataHandle(self, dataDict: dict):
        """
        处理串口控制窗口发过来的信号或数据
        :param dataDict:
        :return:
        """
        dataObj = dataDict.get('data', None)
        typeValue = dataDict.get('type', 'null').strip()
        optionsDict = dataDict.get('options', {})
        self.textBrowserHURead.clear()
        # 收到信号
        if 'TpInt_to_' in typeValue:
            return
        if typeValue == 'status_serial':
            if dataObj == "Serial_Window_Showed":
                pass
            elif dataObj == "Serial_Window_Closed":
                pass
        elif typeValue == 'level_gpio':
            if (dataObj['portNum'] == 2) and (dataObj['level'] == 1):
                self.checkBoxTpIntStatus.setChecked(True)
            if (dataObj['portNum'] == 3) and (dataObj['level'] == 0):
                self.checkBoxIntDHUStatus.setChecked(True)
                if self.checkBoxINTDHU.isChecked():
                    self.checkBoxHUReadSelect.setChecked(True)
                    self.timer_delay.start(int(self.spinBoxDelayTime.value()))
            if (dataObj['portNum'] == 3) and (dataObj['level'] == 1):
                self.checkBoxMCUGPIOStatus.setChecked(True)
        elif typeValue == 'send_hex':
            if dataObj:
                self.checkBoxSendDataStatus.setChecked(True)
        elif typeValue == 'read_hex':
            bytesData = dataObj
            # 使用hexlify函数将bytes数据转换为16进制字符串
            hex_string = binascii.hexlify(bytesData).decode('utf-8').upper()
            # 插入空格
            strData = ' '.join(hex_string[i:i + 2] for i in range(0, len(hex_string), 2))
            self.textBrowserHURead.setText(str(strData))
            # 将bytes转换为bytearray
            bytesArray = bytearray(bytesData)
            if optionsDict.get("addr", "") == "tp":
                # 遍历bytearray，将值为0xFF的修改为0x00
                # for i, byte_value in enumerate(mutable_bytes):
                #     if byte_value == 0xFF:
                #         mutable_bytes[i] = 0x00
                # 将bytearray转换回bytes
                # modified_bytes = bytes(mutable_bytes)
                fingercount = bytesArray[1]
                # 多个起始和结束位置的列表，包括一个非法位置
                positions_list = [(2, 8), (8, 14), (14, 20), (20, 26), (26, 32), (32, 38), (38, 44), (44, 50), (50, 56),
                                  (56, 62)]
                # 切片并保存为数组，同时处理非法位置
                result_array = SliceBytesSafe(bytesArray, positions_list)
                result_list = []
                for position in result_array[:fingercount]:
                    if 0xC0 == position[1]:
                        touchEvent = 'PRESS'
                    elif 0x90 == position[1]:
                        touchEvent = 'MOVE'
                    elif 0xA0 == position[1]:
                        touchEvent = 'RELEASE'
                    else:
                        touchEvent = position[1]
                    # 将 bytes 转换为正整数
                    # byteorder 参数指定字节顺序，'big' 表示高位字节在前，'little' 表示低位字节在前。在网络通信中，通常使用大端（big-endian）字节顺序。
                    result_list.append(
                        f"{position[0]}-{touchEvent}-({int.from_bytes(position[2:4], byteorder='big')},{int.from_bytes(position[4:], byteorder='big')})")
                self.checkBoxHUReadStatus.setChecked(True)
                self.checkBoxINTDHU.setChecked(False)
                self.textBrowser.insertPlainText(f"手指：{fingercount} ，ID-事件-坐标：\n {result_list}  -->")
            elif "EngMode" in optionsDict.get("addr", ""):
                function = bytesArray[2]
                result_list = []
                self.checkBoxEngineerMode.setChecked(True)
                if function == 0x80:
                    result_list = "失败"
                    if bytesArray[3] == 0x01:
                        result_list = "成功"
                        self.checkBoxEngineerMode.setChecked(True)
                    else:
                        self.checkBoxEngineerMode.setChecked(False)
                elif function == 0x81:
                    result_list = "失败"
                    if bytesArray[3] == 0x01:
                        result_list = "成功"
                        self.checkBoxEngineerMode.setChecked(False)
                    else:
                        self.checkBoxEngineerMode.setChecked(True)
                elif function == 0x00:
                    # 多个起始和结束位置的列表，包括一个非法位置
                    version_list = [(4, 19)]
                    # 切片并保存为数组，同时处理非法位置
                    result_array = SliceBytesSafe(bytesArray, version_list)
                    # 将 bytes 转换为字符串
                    result_list = result_array[0].decode('utf-8')
                self.checkBoxHUReadStatus.setChecked(True)
                self.checkBoxINTDHU.setChecked(False)
                self.textBrowser.insertPlainText(f"{result_list}  -->")
            if optionsDict.get("addr", "") == "diagDID":
                dataLen = bytesArray[0]
                serviceId = bytesArray[1]
                didHigh = bytesArray[2]
                didLow = bytesArray[3]
                if (didHigh == 0xFE) and (didLow == 0xAB):
                    temperature = int(bytesArray[5]) - 40
                    self.textBrowser.insertPlainText(f"LCD温度：{temperature}  -->")
            elif self.checkBoxHUReadSelect.isChecked():
                self.checkBoxHUReadStatus.setChecked(True)
                self.checkBoxINTDHU.setChecked(False)
            elif optionsDict.get("addr", "") == "dtc":
                # TODO: 解析DTC
                pass
        elif typeValue == 'rece_protobuf':
            pass
        elif typeValue == 'rece_hex':
            pass
        elif typeValue == 'rece_ascii':
            pass
        elif '_to_TpInt' in typeValue:
            logger.info("收到其他窗口发往Plugin窗口的数据：", typeValue, dataObj)
        # 其他情况
        elif typeValue != None:
            logger.info(f"{typeValue} \t {dataObj}")
        # do something

    def closeEvent(self, event):
        """
        防止误触关闭程序
        :param event:
        :return:
        """
        # 创建一个确认退出的对话框
        reply = QMessageBox.question(
            self, "Confirmation", "Are you sure you want to exit?",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.No
        )
        if reply == QMessageBox.StandardButton.Yes:
            self.CleanupSelf()
            # 用户确认退出，关闭应用
            event.accept()
        else:
            event.ignore()


# 程序入口，测试当前插件文件使用
if __name__ == "__main__":
    app = QApplication(sys.argv)
    myWindow = GWMC01IICWindow()
    myWindow.show()
    sys.exit(app.exec())
